home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 090 / me39src1.arc / EXEC.C < prev    next >
Encoding:
C/C++ Source or Header  |  1987-07-13  |  23.0 KB  |  1,136 lines

  1. /*    This file is for functions dealing with execution of
  2.     commands, command lines, buffers, files and startup files
  3.  
  4.     written 1986 by Daniel Lawrence                */
  5.  
  6. #include    <stdio.h>
  7. #include    "estruct.h"
  8. #include    "edef.h"
  9.  
  10. /* namedcmd:    execute a named command even if it is not bound */
  11.  
  12. namedcmd(f, n)
  13.  
  14. int f, n;    /* command arguments [passed through to command executed] */
  15.  
  16. {
  17.     register (*kfunc)();    /* ptr to the requexted function to bind to */
  18.     int (*getname())();
  19.  
  20.     /* prompt the user to type a named command */
  21.     mlwrite(": ");
  22.  
  23.     /* and now get the function name to execute */
  24.     kfunc = getname();
  25.     if (kfunc == NULL) {
  26.         mlwrite("[No such function]");
  27.         return(FALSE);
  28.     }
  29.  
  30.     /* and then execute the command */
  31.     return((*kfunc)(f, n));
  32. }
  33.  
  34. /*    execcmd:    Execute a command line command to be typed in
  35.             by the user                    */
  36.  
  37. execcmd(f, n)
  38.  
  39. int f, n;    /* default Flag and Numeric argument */
  40.  
  41. {
  42.     register int status;        /* status return */
  43.     char cmdstr[NSTRING];        /* string holding command to execute */
  44.  
  45.     /* get the line wanted */
  46.     if ((status = mlreply(": ", cmdstr, NSTRING)) != TRUE)
  47.         return(status);
  48.  
  49.     execlevel = 0;
  50.     return(docmd(cmdstr));
  51. }
  52.  
  53. /*    docmd:    take a passed string as a command line and translate
  54.         it to be executed as a command. This function will be
  55.         used by execute-command-line and by all source and
  56.         startup files. Lastflag/thisflag is also updated.
  57.  
  58.     format of the command line is:
  59.  
  60.         {# arg} <command-name> {<argument string(s)>}
  61.  
  62. */
  63.  
  64. docmd(cline)
  65.  
  66. char *cline;    /* command line to execute */
  67.  
  68. {
  69.     register int f;        /* default argument flag */
  70.     register int n;        /* numeric repeat value */
  71.     register int i;
  72.     int (*fnc)();        /* function to execute */
  73.     int status;        /* return status of function */
  74.     int oldcle;        /* old contents of clexec flag */
  75.     char *oldestr;        /* original exec string */
  76.     char tkn[NSTRING];    /* next token off of command line */
  77.     int (*fncmatch())();
  78.         
  79.     /* if we are scanning and not executing..go back here */
  80.     if (execlevel)
  81.         return(TRUE);
  82.  
  83.     oldestr = execstr;    /* save last ptr to string to execute */
  84.     execstr = cline;    /* and set this one as current */
  85.  
  86.     /* first set up the default command values */
  87.     f = FALSE;
  88.     n = 1;
  89.     lastflag = thisflag;
  90.     thisflag = 0;
  91.  
  92.     if ((status = macarg(tkn)) != TRUE) {    /* and grab the first token */
  93.         execstr = oldestr;
  94.         return(status);
  95.     }
  96.  
  97.     /* process leadin argument */
  98.     if (gettyp(tkn) != TKCMD) {
  99.         f = TRUE;
  100.         strcpy(tkn, getval(tkn));
  101.         n = atoi(tkn);
  102.  
  103.         /* and now get the command to execute */
  104.         if ((status = macarg(tkn)) != TRUE) {
  105.             execstr = oldestr;
  106.             return(status);    
  107.         }    
  108.     }
  109.  
  110.     /* and match the token to see if it exists */
  111.     if ((fnc = fncmatch(tkn)) == NULL) {
  112.         mlwrite("[No such Function]");
  113.         execstr = oldestr;
  114.         return(FALSE);
  115.     }
  116.     
  117.     /* save the arguments and go execute the command */
  118.     oldcle = clexec;        /* save old clexec flag */
  119.     clexec = TRUE;            /* in cline execution */
  120.     status = (*fnc)(f, n);        /* call the function */
  121.     cmdstatus = status;        /* save the status */
  122.     clexec = oldcle;        /* restore clexec flag */
  123.     execstr = oldestr;
  124.     return(status);
  125. }
  126.  
  127. /* token:    chop a token off a string
  128.         return a pointer past the token
  129. */
  130.  
  131. char *token(src, tok)
  132.  
  133. char *src, *tok;    /* source string, destination token string */
  134.  
  135. {
  136.     register int quotef;    /* is the current string quoted? */
  137.  
  138.     /* first scan past any whitespace in the source string */
  139.     while (*src == ' ' || *src == '\t')
  140.         ++src;
  141.  
  142.     /* scan through the source string */
  143.     quotef = FALSE;
  144.     while (*src) {
  145.         /* process special characters */
  146.         if (*src == '~') {
  147.             ++src;
  148.             if (*src == 0)
  149.                 break;
  150.             switch (*src++) {
  151.                 case 'r':    *tok++ = 13; break;
  152.                 case 'n':    *tok++ = 10; break;
  153.                 case 't':    *tok++ = 9;  break;
  154.                 case 'b':    *tok++ = 8;  break;
  155.                 case 'f':    *tok++ = 12; break;
  156.                 default:    *tok++ = *(src-1);
  157.             }
  158.         } else {
  159.             /* check for the end of the token */
  160.             if (quotef) {
  161.                 if (*src == '"')
  162.                     break;
  163.             } else {
  164.                 if (*src == ' ' || *src == '\t')
  165.                     break;
  166.             }
  167.  
  168.             /* set quote mode if qoute found */
  169.             if (*src == '"')
  170.                 quotef = TRUE;
  171.  
  172.             /* record the character */
  173.             *tok++ = *src++;
  174.         }
  175.     }
  176.  
  177.     /* terminate the token and exit */
  178.     if (*src)
  179.         ++src;
  180.     *tok = 0;
  181.     return(src);
  182. }
  183.  
  184. macarg(tok)    /* get a macro line argument */
  185.  
  186. char *tok;    /* buffer to place argument */
  187.  
  188. {
  189.     int savcle;    /* buffer to store original clexec */
  190.     int status;
  191.  
  192.     savcle = clexec;    /* save execution mode */
  193.     clexec = TRUE;        /* get the argument */
  194.     status = nextarg("", tok, NSTRING, ctoec('\n'));
  195.     clexec = savcle;    /* restore execution mode */
  196.     return(status);
  197. }
  198.  
  199. /*    nextarg:    get the next argument    */
  200.  
  201. nextarg(prompt, buffer, size, terminator)
  202.  
  203. char *prompt;        /* prompt to use if we must be interactive */
  204. char *buffer;        /* buffer to put token into */
  205. char *size;        /* size of the buffer */
  206. int terminator;        /* terminating char to be used on interactive fetch */
  207.  
  208. {
  209.     /* if we are interactive, go get it! */
  210.     if (clexec == FALSE)
  211.         return(getstring(prompt, buffer, size, terminator));
  212.  
  213.     /* grab token and advance past */
  214.     execstr = token(execstr, buffer);
  215.  
  216.     /* evaluate it */
  217.     strcpy(buffer, getval(buffer));
  218.     return(TRUE);
  219. }
  220.  
  221. /*    storemac:    Set up a macro buffer and flag to store all
  222.             executed command lines there            */
  223.  
  224. storemac(f, n)
  225.  
  226. int f;        /* default flag */
  227. int n;        /* macro number to use */
  228.  
  229. {
  230.     register struct BUFFER *bp;    /* pointer to macro buffer */
  231.     char bname[NBUFN];        /* name of buffer to use */
  232.  
  233.     /* must have a numeric argument to this function */
  234.     if (f == FALSE) {
  235.         mlwrite("No macro specified");
  236.         return(FALSE);
  237.     }
  238.  
  239.     /* range check the macro number */
  240.     if (n < 1 || n > 40) {
  241.         mlwrite("Macro number out of range");
  242.         return(FALSE);
  243.     }
  244.  
  245.     /* construct the macro buffer name */
  246.     strcpy(bname, "[Macro xx]");
  247.     bname[7] = '0' + (n / 10);
  248.     bname[8] = '0' + (n % 10);
  249.  
  250.     /* set up the new macro buffer */
  251.     if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  252.         mlwrite("Can not create macro");
  253.         return(FALSE);
  254.     }
  255.  
  256.     /* and make sure it is empty */
  257.     bclear(bp);
  258.  
  259.     /* and set the macro store pointers to it */
  260.     mstore = TRUE;
  261.     bstore = bp;
  262.     return(TRUE);
  263. }
  264.  
  265. #if    PROC
  266. /*    storeproc:    Set up a procedure buffer and flag to store all
  267.             executed command lines there            */
  268.  
  269. storeproc(f, n)
  270.  
  271. int f;        /* default flag */
  272. int n;        /* macro number to use */
  273.  
  274. {
  275.     register struct BUFFER *bp;    /* pointer to macro buffer */
  276.     register int status;        /* return status */
  277.     char bname[NBUFN];        /* name of buffer to use */
  278.  
  279.     /* a numeric argument means its a numbered macro */
  280.     if (f == TRUE)
  281.         return(storemac(f, n));
  282.  
  283.     /* get the name of the procedure */
  284.         if ((status = mlreply("Procedure name: ", &bname[1], NBUFN-2)) != TRUE)
  285.                 return(status);
  286.  
  287.     /* construct the macro buffer name */
  288.     bname[0] = '[';
  289.     strcat(bname, "]");
  290.  
  291.     /* set up the new macro buffer */
  292.     if ((bp = bfind(bname, TRUE, BFINVS)) == NULL) {
  293.         mlwrite("Can not create macro");
  294.         return(FALSE);
  295.     }
  296.  
  297.     /* and make sure it is empty */
  298.     bclear(bp);
  299.  
  300.     /* and set the macro store pointers to it */
  301.     mstore = TRUE;
  302.     bstore = bp;
  303.     return(TRUE);
  304. }
  305.  
  306. /*    execproc:    Execute a procedure                */
  307.  
  308. execproc(f, n)
  309.  
  310. int f, n;    /* default flag and numeric arg */
  311.  
  312. {
  313.         register BUFFER *bp;        /* ptr to buffer to execute */
  314.         register int status;        /* status return */
  315.         char bufn[NBUFN+2];        /* name of buffer to execute */
  316.  
  317.     /* find out what buffer the user wants to execute */
  318.         if ((status = mlreply("Execute procedure: ", &bufn[1], NBUFN)) != TRUE)
  319.                 return(status);
  320.  
  321.     /* construct the buffer name */
  322.     bufn[0] = '[';
  323.     strcat(bufn, "]");
  324.  
  325.     /* find the pointer to that buffer */
  326.         if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  327.         mlwrite("No such procedure");
  328.                 return(FALSE);
  329.         }
  330.  
  331.     /* and now execute it as asked */
  332.     while (n-- > 0)
  333.         if ((status = dobuf(bp)) != TRUE)
  334.             return(status);
  335.     return(TRUE);
  336. }
  337. #endif
  338.  
  339. /*    execbuf:    Execute the contents of a buffer of commands    */
  340.  
  341. execbuf(f, n)
  342.  
  343. int f, n;    /* default flag and numeric arg */
  344.  
  345. {
  346.         register BUFFER *bp;        /* ptr to buffer to execute */
  347.         register int status;        /* status return */
  348.         char bufn[NSTRING];        /* name of buffer to execute */
  349.  
  350.     /* find out what buffer the user wants to execute */
  351.         if ((status = mlreply("Execute buffer: ", bufn, NBUFN)) != TRUE)
  352.                 return(status);
  353.  
  354.     /* find the pointer to that buffer */
  355.         if ((bp=bfind(bufn, FALSE, 0)) == NULL) {
  356.         mlwrite("No such buffer");
  357.                 return(FALSE);
  358.         }
  359.  
  360.     /* and now execute it as asked */
  361.     while (n-- > 0)
  362.         if ((status = dobuf(bp)) != TRUE)
  363.             return(status);
  364.     return(TRUE);
  365. }
  366.  
  367. /*    dobuf:    execute the contents of the buffer pointed to
  368.         by the passed BP
  369.  
  370.     Directives start with a "!" and include:
  371.  
  372.     !endm        End a macro
  373.     !if (cond)    conditional execution
  374.     !else
  375.     !endif
  376.     !return        Return (terminating current macro)
  377.     !goto <label>    Jump to a label in the current macro
  378.     !force        Force macro to continue...even if command fails
  379.     !while (cond)    Execute a loop if the condition is true
  380.     !endwhile
  381.     
  382.     Line Labels begin with a "*" as the first nonblank char, like:
  383.  
  384.     *LBL01
  385. */
  386.  
  387. dobuf(bp)
  388.  
  389. BUFFER *bp;    /* buffer to execute */
  390.  
  391. {
  392.         register int status;    /* status return */
  393.     register LINE *lp;    /* pointer to line to execute */
  394.     register LINE *hlp;    /* pointer to line header */
  395.     register LINE *glp;    /* line to goto */
  396.     LINE *mp;        /* Macro line storage temp */
  397.     int dirnum;        /* directive index */
  398.     int linlen;        /* length of line to execute */
  399.     int i;            /* index */
  400.     int force;        /* force TRUE result? */
  401.     WINDOW *wp;        /* ptr to windows to scan */
  402.     WHBLOCK *whlist;    /* ptr to !WHILE list */
  403.     WHBLOCK *scanner;    /* ptr during scan */
  404.     WHBLOCK *whtemp;    /* temporary ptr to a WHBLOCK */
  405.     char *einit;        /* initial value of eline */
  406.     char *eline;        /* text of line to execute */
  407.     char tkn[NSTRING];    /* buffer to evaluate an expresion in */
  408.  
  409. #if    DEBUGM
  410.     char *sp;            /* temp for building debug string */
  411.     register char *ep;    /* ptr to end of outline */
  412. #endif
  413.  
  414.     /* clear IF level flags/while ptr */
  415.     execlevel = 0;
  416.     whlist = NULL;
  417.     scanner = NULL;
  418.  
  419.     /* scan the buffer to execute, building WHILE header blocks */
  420.     hlp = bp->b_linep;
  421.     lp = hlp->l_fp;
  422.     while (lp != hlp) {
  423.         /* scan the current line */
  424.         eline = lp->l_text;
  425.         i = lp->l_used;
  426.  
  427.         /* trim leading whitespace */
  428.         while (i-- > 0 && (*eline == ' ' || *eline == '\t'))
  429.             ++eline;
  430.  
  431.         /* if theres nothing here, don't bother */
  432.         if (i <= 0)
  433.             goto nxtscan;
  434.  
  435.         /* if is a while directive, make a block... */
  436.         if (eline[0] == '!' && eline[1] == 'w' && eline[2] == 'h') {
  437.             whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  438.             if (whtemp == NULL) {
  439. noram:                mlwrite("%%Out of memory during while scan");
  440. failexit:            freewhile(scanner);
  441.                 freewhile(whlist);
  442.                 return(FALSE);
  443.             }
  444.             whtemp->w_begin = lp;
  445.             whtemp->w_type = BTWHILE;
  446.             whtemp->w_next = scanner;
  447.             scanner = whtemp;
  448.         }
  449.  
  450.         /* if is a BREAK directive, make a block... */
  451.         if (eline[0] == '!' && eline[1] == 'b' && eline[2] == 'r') {
  452.             if (scanner == NULL) {
  453.                 mlwrite("%%!BREAK outside of any !WHILE loop");
  454.                 goto failexit;
  455.             }
  456.             whtemp = (WHBLOCK *)malloc(sizeof(WHBLOCK));
  457.             if (whtemp == NULL)
  458.                 goto noram;
  459.             whtemp->w_begin = lp;
  460.             whtemp->w_type = BTBREAK;
  461.             whtemp->w_next = scanner;
  462.             scanner = whtemp;
  463.         }
  464.  
  465.         /* if it is an endwhile directive, record the spot... */
  466.         if (eline[0] == '!' && strncmp(&eline[1], "endw", 4) == 0) {
  467.             if (scanner == NULL) {
  468.                 mlwrite("%%!ENDWHILE with no preceding !WHILE in '%s'",
  469.                     bp->b_bname);
  470.                 goto failexit;
  471.             }
  472.             /* move top records from the scanner list to the
  473.                whlist until we have moved all BREAK records
  474.                and one WHILE record */
  475.             do {
  476.                 scanner->w_end = lp;
  477.                 whtemp = whlist;
  478.                 whlist = scanner;
  479.                 scanner = scanner->w_next;
  480.                 whlist->w_next = whtemp;
  481.             } while (whlist->w_type == BTBREAK);
  482.         }
  483.  
  484. nxtscan:    /* on to the next line */
  485.         lp = lp->l_fp;
  486.     }
  487.  
  488.     /* while and endwhile should match! */
  489.     if (scanner != NULL) {
  490.         mlwrite("%%!WHILE with no matching !ENDWHILE in '%s'",
  491.             bp->b_bname);
  492.         goto failexit;
  493.     }
  494.  
  495.     /* let the first command inherit the flags from the last one..*/
  496.     thisflag = lastflag;
  497.  
  498.     /* starting at the beginning of the buffer */
  499.     hlp = bp->b_linep;
  500.     lp = hlp->l_fp;
  501.     while (lp != hlp) {
  502.         /* allocate eline and copy macro line to it */
  503.         linlen = lp->l_used;
  504.         if ((einit = eline = malloc(linlen+1)) == NULL) {
  505.             mlwrite("%%Out of Memory during macro execution");
  506.             freewhile(whlist);
  507.             return(FALSE);
  508.         }
  509.         strncpy(eline, lp->l_text, linlen);
  510.         eline[linlen] = 0;    /* make sure it ends */
  511.  
  512.         /* trim leading whitespace */
  513.         while (*eline == ' ' || *eline == '\t')
  514.             ++eline;
  515.  
  516.         /* dump comments and blank lines */
  517.         if (*eline == ';' || *eline == 0)
  518.             goto onward;
  519.  
  520. #if    DEBUGM
  521.         /* if $debug == TRUE, every line to execute
  522.            gets echoed and a key needs to be pressed to continue
  523.            ^G will abort the command */
  524.     
  525.         if (macbug) {
  526.             strcpy(outline, "<<<");
  527.     
  528.             /* debug macro name */
  529.             strcat(outline, bp->b_bname);
  530.             strcat(outline, ":");
  531.     
  532.             /* debug if levels */
  533.             strcat(outline, itoa(execlevel));
  534.             strcat(outline, ":");
  535.  
  536.             /* and lastly the line */
  537.             strcat(outline, eline);
  538.             strcat(outline, ">>>");
  539.     
  540.             /* change all '%' to ':' so mlwrite won't expect arguments */
  541.             sp = outline;
  542.             while (*sp)
  543.             if (*sp++ == '%') {
  544.                 /* advance to the end */
  545.                 ep = --sp;
  546.                 while (*ep++)
  547.                     ;
  548.                 /* null terminate the string one out */
  549.                 *(ep + 1) = 0;
  550.                 /* copy backwards */
  551.                 while(ep-- > sp)
  552.                     *(ep + 1) = *ep;
  553.  
  554.                 /* and advance sp past the new % */
  555.                 sp += 2;                    
  556.             }
  557.     
  558.             /* write out the debug line */
  559.             mlforce(outline);
  560.             update(TRUE);
  561.     
  562.             /* and get the keystroke */
  563.             if (get1key() == abortc) {
  564.                 mlforce("[Macro aborted]");
  565.                 freewhile(whlist);
  566.                 return(FALSE);
  567.             }
  568.         }
  569. #endif
  570.  
  571.         /* Parse directives here.... */
  572.         dirnum = -1;
  573.         if (*eline == '!') {
  574.             /* Find out which directive this is */
  575.             ++eline;
  576.             for (dirnum = 0; dirnum < NUMDIRS; dirnum++)
  577.                 if (strncmp(eline, dname[dirnum],
  578.                             strlen(dname[dirnum])) == 0)
  579.                     break;
  580.  
  581.             /* and bitch if it's illegal */
  582.             if (dirnum == NUMDIRS) {
  583.                 mlwrite("%%Unknown Directive");
  584.                 freewhile(whlist);
  585.                 return(FALSE);
  586.             }
  587.  
  588.             /* service only the !ENDM macro here */
  589.             if (dirnum == DENDM) {
  590.                 mstore = FALSE;
  591.                 bstore = NULL;
  592.                 goto onward;
  593.             }
  594.  
  595.             /* restore the original eline....*/
  596.             --eline;
  597.         }
  598.  
  599.         /* if macro store is on, just salt this away */
  600.         if (mstore) {
  601.             /* allocate the space for the line */
  602.             linlen = strlen(eline);
  603.             if ((mp=lalloc(linlen)) == NULL) {
  604.                 mlwrite("Out of memory while storing macro");
  605.                 return (FALSE);
  606.             }
  607.     
  608.             /* copy the text into the new line */
  609.             for (i=0; i<linlen; ++i)
  610.                 lputc(mp, i, eline[i]);
  611.     
  612.             /* attach the line to the end of the buffer */
  613.                    bstore->b_linep->l_bp->l_fp = mp;
  614.             mp->l_bp = bstore->b_linep->l_bp;
  615.             bstore->b_linep->l_bp = mp;
  616.             mp->l_fp = bstore->b_linep;
  617.             goto onward;
  618.         }
  619.     
  620.  
  621.         force = FALSE;
  622.  
  623.         /* dump comments */
  624.         if (*eline == '*')
  625.             goto onward;
  626.  
  627.         /* now, execute directives */
  628.         if (dirnum != -1) {
  629.             /* skip past the directive */
  630.             while (*eline && *eline != ' ' && *eline != '\t')
  631.                 ++eline;
  632.             execstr = eline;
  633.  
  634.             switch (dirnum) {
  635.             case DIF:    /* IF directive */
  636.                 /* grab the value of the logical exp */
  637.                 if (execlevel == 0) {
  638.                     if (macarg(tkn) != TRUE)
  639.                         goto eexec;
  640.                     if (stol(tkn) == FALSE)
  641.                         ++execlevel;
  642.                 } else
  643.                     ++execlevel;
  644.                 goto onward;
  645.  
  646.             case DWHILE:    /* WHILE directive */
  647.                 /* grab the value of the logical exp */
  648.                 if (execlevel == 0) {
  649.                     if (macarg(tkn) != TRUE)
  650.                         goto eexec;
  651.                     if (stol(tkn) == TRUE)
  652.                         goto onward;
  653.                 }
  654.                 /* drop down and act just like !BREAK */
  655.  
  656.             case DBREAK:    /* BREAK directive */
  657.                 if (dirnum == DBREAK && execlevel)
  658.                     goto onward;
  659.  
  660.                 /* jump down to the endwhile */
  661.                 /* find the right while loop */
  662.                 whtemp = whlist;
  663.                 while (whtemp) {
  664.                     if (whtemp->w_begin == lp)
  665.                         break;
  666.                     whtemp = whtemp->w_next;
  667.                 }
  668.             
  669.                 if (whtemp == NULL) {
  670.                     mlwrite("%%Internal While loop error");
  671.                     freewhile(whlist);
  672.                     return(FALSE);
  673.                 }
  674.             
  675.                 /* reset the line pointer back.. */
  676.                 lp = whtemp->w_end;
  677.                 goto onward;
  678.  
  679.             case DELSE:    /* ELSE directive */
  680.                 if (execlevel == 1)
  681.                     --execlevel;
  682.                 else if (execlevel == 0 )
  683.                     ++execlevel;
  684.                 goto onward;
  685.  
  686.             case DENDIF:    /* ENDIF directive */
  687.                 if (execlevel)
  688.                     --execlevel;
  689.                 goto onward;
  690.  
  691.             case DGOTO:    /* GOTO directive */
  692.                 /* .....only if we are currently executing */
  693.                 if (execlevel == 0) {
  694.  
  695.                     /* grab label to jump to */
  696.                     eline = token(eline, golabel);
  697.                     linlen = strlen(golabel);
  698.                     glp = hlp->l_fp;
  699.                     while (glp != hlp) {
  700.                         if (*glp->l_text == '*' &&
  701.                             (strncmp(&glp->l_text[1], golabel,
  702.                                     linlen) == 0)) {
  703.                             lp = glp;
  704.                             goto onward;
  705.                         }
  706.                         glp = glp->l_fp;
  707.                     }
  708.                     mlwrite("%%No such label");
  709.                     freewhile(whlist);
  710.                     return(FALSE);
  711.                 }
  712.                 goto onward;
  713.     
  714.             case DRETURN:    /* RETURN directive */
  715.                 if (execlevel == 0)
  716.                     goto eexec;
  717.                 goto onward;
  718.  
  719.             case DENDWHILE:    /* ENDWHILE directive */
  720.                 if (execlevel) {
  721.                     --execlevel;
  722.                     goto onward;
  723.                 } else {
  724.                     /* find the right while loop */
  725.                     whtemp = whlist;
  726.                     while (whtemp) {
  727.                         if (whtemp->w_type == BTWHILE &&
  728.                             whtemp->w_end == lp)
  729.                             break;
  730.                         whtemp = whtemp->w_next;
  731.                     }
  732.         
  733.                     if (whtemp == NULL) {
  734.                         mlwrite("%%Internal While loop error");
  735.                         freewhile(whlist);
  736.                         return(FALSE);
  737.                     }
  738.         
  739.                     /* reset the line pointer back.. */
  740.                     lp = whtemp->w_begin->l_bp;
  741.                     goto onward;
  742.                 }
  743.  
  744.             case DFORCE:    /* FORCE directive */
  745.                 force = TRUE;
  746.  
  747.             }
  748.         }
  749.  
  750.         /* execute the statement */
  751.         status = docmd(eline);
  752.         if (force)        /* force the status */
  753.             status = TRUE;
  754.  
  755.         /* check for a command error */
  756.         if (status != TRUE) {
  757.             /* look if buffer is showing */
  758.             wp = wheadp;
  759.             while (wp != NULL) {
  760.                 if (wp->w_bufp == bp) {
  761.                     /* and point it */
  762.                     wp->w_dotp = lp;
  763.                     wp->w_doto = 0;
  764.                     wp->w_flag |= WFHARD;
  765.                 }
  766.                 wp = wp->w_wndp;
  767.             }
  768.             /* in any case set the buffer . */
  769.             bp->b_dotp = lp;
  770.             bp->b_doto = 0;
  771.             free(einit);
  772.             execlevel = 0;
  773.             freewhile(whlist);
  774.             return(status);
  775.         }
  776.  
  777. onward:        /* on to the next line */
  778.         free(einit);
  779.         lp = lp->l_fp;
  780.     }
  781.  
  782. eexec:    /* exit the current function */
  783.     execlevel = 0;
  784.     freewhile(whlist);
  785.         return(TRUE);
  786. }
  787.  
  788. freewhile(wp)    /* free a list of while block pointers */
  789.  
  790. WHBLOCK *wp;    /* head of structure to free */
  791.  
  792. {
  793.     if (wp == NULL)
  794.         return;
  795.     if (wp->w_next)
  796.         freewhile(wp->w_next);
  797.     free(wp);
  798. }
  799.  
  800. execfile(f, n)    /* execute a series of commands in a file */
  801.  
  802. int f, n;    /* default flag and numeric arg to pass on to file */
  803.  
  804. {
  805.     register int status;    /* return status of name query */
  806.     char fname[NSTRING];    /* name of file to execute */
  807.     char *fspec;        /* full file spec */
  808.  
  809.     if ((status = mlreply("File to execute: ", fname, NSTRING -1)) != TRUE)
  810.         return(status);
  811.  
  812. #if    1
  813.     /* look up the path for the file */
  814.     fspec = flook(fname, TRUE);
  815.  
  816.     /* if it isn't around */
  817.     if (fspec == NULL)
  818.         return(FALSE);
  819.  
  820. #endif
  821.     /* otherwise, execute it */
  822.     while (n-- > 0)
  823.         if ((status=dofile(fspec)) != TRUE)
  824.             return(status);
  825.  
  826.     return(TRUE);
  827. }
  828.  
  829. /*    dofile:    yank a file into a buffer and execute it
  830.         if there are no errors, delete the buffer on exit */
  831.  
  832. dofile(fname)
  833.  
  834. char *fname;    /* file name to execute */
  835.  
  836. {
  837.     register BUFFER *bp;    /* buffer to place file to exeute */
  838.     register BUFFER *cb;    /* temp to hold current buf while we read */
  839.     register int status;    /* results of various calls */
  840.     char bname[NBUFN];    /* name of buffer */
  841.  
  842.     makename(bname, fname);        /* derive the name of the buffer */
  843.     if ((bp = bfind(bname, TRUE, 0)) == NULL) /* get the needed buffer */
  844.         return(FALSE);
  845.  
  846.     bp->b_mode = MDVIEW;    /* mark the buffer as read only */
  847.     cb = curbp;        /* save the old buffer */
  848.     curbp = bp;        /* make this one current */
  849.     /* and try to read in the file to execute */
  850.     if ((status = readin(fname, FALSE)) != TRUE) {
  851.         curbp = cb;    /* restore the current buffer */
  852.         return(status);
  853.     }
  854.  
  855.     /* go execute it! */
  856.     curbp = cb;        /* restore the current buffer */
  857.     if ((status = dobuf(bp)) != TRUE)
  858.         return(status);
  859.  
  860.     /* if not displayed, remove the now unneeded buffer and exit */
  861.     if (bp->b_nwnd == 0)
  862.         zotbuf(bp);
  863.     return(TRUE);
  864. }
  865.  
  866. /*    cbuf:    Execute the contents of a numbered buffer    */
  867.  
  868. cbuf(f, n, bufnum)
  869.  
  870. int f, n;    /* default flag and numeric arg */
  871. int bufnum;    /* number of buffer to execute */
  872.  
  873. {
  874.         register BUFFER *bp;        /* ptr to buffer to execute */
  875.         register int status;        /* status return */
  876.     static char bufname[] = "[Macro xx]";
  877.  
  878.     /* make the buffer name */
  879.     bufname[7] = '0' + (bufnum / 10);
  880.     bufname[8] = '0' + (bufnum % 10);
  881.  
  882.     /* find the pointer to that buffer */
  883.         if ((bp=bfind(bufname, FALSE, 0)) == NULL) {
  884.             mlwrite("Macro not defined");
  885.                 return(FALSE);
  886.         }
  887.  
  888.     /* and now execute it as asked */
  889.     while (n-- > 0)
  890.         if ((status = dobuf(bp)) != TRUE)
  891.             return(status);
  892.     return(TRUE);
  893. }
  894.  
  895. cbuf1(f, n)
  896.  
  897. {
  898.     cbuf(f, n, 1);
  899. }
  900.  
  901. cbuf2(f, n)
  902.  
  903. {
  904.     cbuf(f, n, 2);
  905. }
  906.  
  907. cbuf3(f, n)
  908.  
  909. {
  910.     cbuf(f, n, 3);
  911. }
  912.  
  913. cbuf4(f, n)
  914.  
  915. {
  916.     cbuf(f, n, 4);
  917. }
  918.  
  919. cbuf5(f, n)
  920.  
  921. {
  922.     cbuf(f, n, 5);
  923. }
  924.  
  925. cbuf6(f, n)
  926.  
  927. {
  928.     cbuf(f, n, 6);
  929. }
  930.  
  931. cbuf7(f, n)
  932.  
  933. {
  934.     cbuf(f, n, 7);
  935. }
  936.  
  937. cbuf8(f, n)
  938.  
  939. {
  940.     cbuf(f, n, 8);
  941. }
  942.  
  943. cbuf9(f, n)
  944.  
  945. {
  946.     cbuf(f, n, 9);
  947. }
  948.  
  949. cbuf10(f, n)
  950.  
  951. {
  952.     cbuf(f, n, 10);
  953. }
  954.  
  955. cbuf11(f, n)
  956.  
  957. {
  958.     cbuf(f, n, 11);
  959. }
  960.  
  961. cbuf12(f, n)
  962.  
  963. {
  964.     cbuf(f, n, 12);
  965. }
  966.  
  967. cbuf13(f, n)
  968.  
  969. {
  970.     cbuf(f, n, 13);
  971. }
  972.  
  973. cbuf14(f, n)
  974.  
  975. {
  976.     cbuf(f, n, 14);
  977. }
  978.  
  979. cbuf15(f, n)
  980.  
  981. {
  982.     cbuf(f, n, 15);
  983. }
  984.  
  985. cbuf16(f, n)
  986.  
  987. {
  988.     cbuf(f, n, 16);
  989. }
  990.  
  991. cbuf17(f, n)
  992.  
  993. {
  994.     cbuf(f, n, 17);
  995. }
  996.  
  997. cbuf18(f, n)
  998.  
  999. {
  1000.     cbuf(f, n, 18);
  1001. }
  1002.  
  1003. cbuf19(f, n)
  1004.  
  1005. {
  1006.     cbuf(f, n, 19);
  1007. }
  1008.  
  1009. cbuf20(f, n)
  1010.  
  1011. {
  1012.     cbuf(f, n, 20);
  1013. }
  1014.  
  1015. cbuf21(f, n)
  1016.  
  1017. {
  1018.     cbuf(f, n, 21);
  1019. }
  1020.  
  1021. cbuf22(f, n)
  1022.  
  1023. {
  1024.     cbuf(f, n, 22);
  1025. }
  1026.  
  1027. cbuf23(f, n)
  1028.  
  1029. {
  1030.     cbuf(f, n, 23);
  1031. }
  1032.  
  1033. cbuf24(f, n)
  1034.  
  1035. {
  1036.     cbuf(f, n, 24);
  1037. }
  1038.  
  1039. cbuf25(f, n)
  1040.  
  1041. {
  1042.     cbuf(f, n, 25);
  1043. }
  1044.  
  1045. cbuf26(f, n)
  1046.  
  1047. {
  1048.     cbuf(f, n, 26);
  1049. }
  1050.  
  1051. cbuf27(f, n)
  1052.  
  1053. {
  1054.     cbuf(f, n, 27);
  1055. }
  1056.  
  1057. cbuf28(f, n)
  1058.  
  1059. {
  1060.     cbuf(f, n, 28);
  1061. }
  1062.  
  1063. cbuf29(f, n)
  1064.  
  1065. {
  1066.     cbuf(f, n, 29);
  1067. }
  1068.  
  1069. cbuf30(f, n)
  1070.  
  1071. {
  1072.     cbuf(f, n, 30);
  1073. }
  1074.  
  1075. cbuf31(f, n)
  1076.  
  1077. {
  1078.     cbuf(f, n, 31);
  1079. }
  1080.  
  1081. cbuf32(f, n)
  1082.  
  1083. {
  1084.     cbuf(f, n, 32);
  1085. }
  1086.  
  1087. cbuf33(f, n)
  1088.  
  1089. {
  1090.     cbuf(f, n, 33);
  1091. }
  1092.  
  1093. cbuf34(f, n)
  1094.  
  1095. {
  1096.     cbuf(f, n, 34);
  1097. }
  1098.  
  1099. cbuf35(f, n)
  1100.  
  1101. {
  1102.     cbuf(f, n, 35);
  1103. }
  1104.  
  1105. cbuf36(f, n)
  1106.  
  1107. {
  1108.     cbuf(f, n, 36);
  1109. }
  1110.  
  1111. cbuf37(f, n)
  1112.  
  1113. {
  1114.     cbuf(f, n, 37);
  1115. }
  1116.  
  1117. cbuf38(f, n)
  1118.  
  1119. {
  1120.     cbuf(f, n, 38);
  1121. }
  1122.  
  1123. cbuf39(f, n)
  1124.  
  1125. {
  1126.     cbuf(f, n, 39);
  1127. }
  1128.  
  1129. cbuf40(f, n)
  1130.  
  1131. {
  1132.     cbuf(f, n, 40);
  1133. }
  1134.  
  1135.  
  1136.